package com.lanxiao.cloud.gateway.application;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.lanxiao.cloud.gateway.api.GatewayRouteDubboApi;
import com.lanxiao.cloud.gateway.api.dto.GatewayRouteDubboDto;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @author ：qiaoliang
 * @date ：2021-09-09
 */
@Component
public class RouteDefinitionManager implements RouteDefinitionRepository {

  private static final Logger log = LoggerFactory.getLogger(RouteDefinitionManager.class);

  private Map<String, RouteDefinition> routes = Collections.synchronizedMap(new LinkedHashMap());

  @DubboReference
  private GatewayRouteDubboApi gatewayRouteDubboApi;

  /**
   *  初始换网关路由
   *
   * @author ：qiaoliang

   * @date 2021-09-03 13:47
   */
  public void gatewayRouteInit() {
    log.info("==================== 初始化网关路由 Start ====================");
    this.deleteAll();
    this.saveAll();
    log.info("==================== 初始化网关路由 End ====================");
  }

  private void deleteAll() {
    log.info("删除所有网关路由.....");
    this.routes = Collections.synchronizedMap(new LinkedHashMap());
  }

  private void saveAll() {
    log.info("重新加载网关路由.....");
    final List<GatewayRouteDubboDto> gatewayRouteDubboDtoList = gatewayRouteDubboApi.all();
    if(CollUtil.isNotEmpty(gatewayRouteDubboDtoList)) {
      gatewayRouteDubboDtoList.forEach(gatewayRouteDubboDto ->
          this.routes.put(gatewayRouteDubboDto.getServiceId(), this.handleData(gatewayRouteDubboDto)));
    }
  }

  /***
   *  路由数据转换公共方法
   *
   * @author ：qiaoliang
   * @param gatewayRoute : 路由信息
   * @return org.springframework.cloud.gateway.route.RouteDefinition
   * @date 2021-08-23 14:23
   */
  private RouteDefinition handleData(GatewayRouteDubboDto gatewayRoute) {
    RouteDefinition definition = new RouteDefinition();
    Map<String, String> predicateParams = new HashMap<>(8);
    PredicateDefinition predicate = new PredicateDefinition();
    FilterDefinition filterDefinition = new FilterDefinition();
    Map<String, String> filterParams = new HashMap<>(8);
    URI uri = null;
    if(gatewayRoute.getUri().startsWith("http")) {
      //http地址
      uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();
    }else {
      //注册中心
      uri = UriComponentsBuilder.fromUriString("lb://"+gatewayRoute.getUri()).build().toUri();
    }
    definition.setId(gatewayRoute.getServiceId());
    // 名称是固定的，spring gateway会根据名称找对应的PredicateFactory
    predicate.setName("Path");
    predicateParams.put("pattern",gatewayRoute.getPredicates());
    predicate.setArgs(predicateParams);
    // 名称是固定的, 路径去前缀
    filterDefinition.setName("StripPrefix");
    filterParams.put("_genkey_0", gatewayRoute.getFilters());
    filterDefinition.setArgs(filterParams);
    definition.setPredicates(Collections.singletonList(predicate));
    definition.setFilters(Collections.singletonList(filterDefinition));
    definition.setUri(uri);
    definition.setOrder(gatewayRoute.getSort());
    return definition;
  }

  @Override
  public Flux<RouteDefinition> getRouteDefinitions() {
    return Flux.fromIterable(this.routes.values());
  }

  @Override
  public Mono<Void> save(Mono<RouteDefinition> route) {
    return Mono.empty();
  }

  @Override
  public Mono<Void> delete(Mono<String> routeId) {
    return Mono.empty();
  }
}
